package com.jxpanda.spring.module.auth.core.authentication.converter;


import com.jxpanda.infrastructure.spring.toolkit.WebfluxKit;
import com.jxpanda.spring.module.auth.core.authentication.token.CollaborativeAuthenticationToken;
import com.jxpanda.spring.module.auth.endpoint.OAuth2Request;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 负责把OAuth2TokenRequest转换为Authentication对象
 * Authentication对象是后续Spring security认证流程的入参对象
 */
public class CollaborativeAuthenticationConverter implements ServerAuthenticationConverter {

    private final ReactiveClientRegistrationRepository reactiveClientRegistrationRepository;

    private final PathPatternParserServerWebExchangeMatcher webExchangeMatcher;

    public CollaborativeAuthenticationConverter(ReactiveClientRegistrationRepository reactiveClientRegistrationRepository, PathPatternParserServerWebExchangeMatcher webExchangeMatcher) {
        this.reactiveClientRegistrationRepository = reactiveClientRegistrationRepository;
        this.webExchangeMatcher = webExchangeMatcher;
    }

    @Override
    public Mono<Authentication> convert(ServerWebExchange exchange) {
        return webExchangeMatcher.matches(exchange)
                .filter(ServerWebExchangeMatcher.MatchResult::isMatch)
                .map(matchResult -> matchResult.getVariables().get("registrationId").toString())
                .flatMap(registrationId -> this.apply(exchange, registrationId));
    }

    protected Mono<CollaborativeAuthenticationToken> apply(ServerWebExchange exchange, String registrationId) {
        return WebfluxKit.readBody(exchange, OAuth2Request.class)
                .switchIfEmpty(Mono.error(new IllegalArgumentException("Unsupported grant type")))
                .flatMap(oAuth2Request -> this.reactiveClientRegistrationRepository.findByRegistrationId(registrationId)
                        .map(clientRegistration -> new CollaborativeAuthenticationToken(oAuth2Request, clientRegistration)));
    }



}
